﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LimitedScopeTrader.Data.StocksDataSetTableAdapters;
using LimitedScopeTrader.Data;
using System.Runtime.Serialization;
using System.Web;
using System.IO;
using System.Net;

namespace LimitedScopeTrader.Business
{
    #region Custom Exceptions
    [Serializable]
    public class DataLoadException : Exception
    {
        string tableThatFailed = null;

        public DataLoadException()
        {
            tableThatFailed = ""; 
        }

        public DataLoadException(string message, string table)
            : base(message, new Exception("The following table couldn't be loaded: " + table))
        {
            
        }

        protected DataLoadException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            base.GetObjectData(info, context);

            if (info != null)
            {
                info.AddValue("tableThatFailed", this.tableThatFailed);
            }
        }
    }

    [Serializable]
    public class DataUpdateException : Exception
    {
        string tableThatFailed = null;

        public DataUpdateException()
        {
            tableThatFailed = "";
        }

        public DataUpdateException(string message, string table)
            : base(message, new Exception("Could not update data in the following table: " + table))
        {

        }

        protected DataUpdateException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            base.GetObjectData(info, context);

            if (info != null)
            {
                info.AddValue("tableThatFailed", this.tableThatFailed);
            }
        }
    }
    #endregion

    public class LimitedScopeBusiness
    {         
        
        /// <summary>
        /// Adds an account record
        /// </summary>
        /// <param name="acctId">Account Id</param>
        /// <param name="acctName">Account Name</param>
        /// <param name="pswd">Password</param>
        /// <returns>True if the account was succesfully added, otherwise false</returns>
        public int AddAccount(string acctId, string acctName, string pswd)
        {
            // This is the hook to the stored procedures data layer
            QueriesTableAdapter dataAdapters = new QueriesTableAdapter();
            int retval = -1;
            try
            {
                retval = dataAdapters.AddAccount(acctId, acctName, pswd);
                if (retval < 0)
                {
                    throw new DataUpdateException("Error adding account", "Account");
                }
            }
            catch (Exception ex)
            {
                throw new DataUpdateException(ex.Message, "Account");
            }

            return retval;
        }

        /// <summary>
        /// Addes a trade record to the database.
        /// </summary>
        /// <param name="tradeType">Trade type</param>
        /// <param name="ticker">Ticker</param>
        /// <param name="qty">Quantity</param>
        /// <param name="acctId">Account id</param>
        /// <param name="price">Price</param>
        /// <returns>True if the trade was succesfully added, otherwise false</returns>
        public int AddTrade(string tradeType, string ticker, double qty, string acctId, double price, DateTime dt)
        {
            int retval = -1;
            try
            {
                // This is the hook to the stored procedures data layer
                QueriesTableAdapter dataAdapters = new QueriesTableAdapter();
                retval = dataAdapters.AddNewTrade(tradeType, ticker, qty, acctId, price, dt);
                if (retval < 0)
                {
                    throw new DataUpdateException("Error adding trade", "Trades");
                }
            }
            catch (Exception ex)
            {
                throw new DataUpdateException(ex.Message, "Trades");
            }
            return retval;
        }

        /// <summary>
        /// Addes a trade record to the database.
        /// </summary>
        /// <param name="tradeType">Trade type</param>
        /// <param name="ticker">Ticker</param>
        /// <param name="qty">Quantity</param>
        /// <param name="acctId">Account id</param>
        /// <param name="price">Price</param>
        /// <param name="dt">Transaction Date</param>
        /// <returns>True if the trade was succesfully added, otherwise false</returns>
        public int AddTransaction(string tradeType, string ticker, double qty, string acctId, double price, DateTime dt)
        {
            int retval = -1;
            try
            {
                // This is the hook to the stored procedures data layer
                QueriesTableAdapter dataAdapters = new QueriesTableAdapter();
                retval = dataAdapters.AddNewTransaction(tradeType, ticker, qty, acctId, price, dt);
                if (retval < 0)
                {
                    throw new DataUpdateException("Error adding transaction", "Trades");
                }
            }
            catch (Exception ex)
            {
                throw new DataUpdateException(ex.Message, "Trades");
            }
            return retval;
        }


        /// <summary>
        /// Updates an account record
        /// </summary>
        /// <param name="acctId">Account Id</param>
        /// <param name="acctName">Account name</param>
        /// <param name="pswd">password</param>
        /// <returns>True if the record was successfully updated, otherwise false</returns>
        public int UpdateAccount(string acctId, string acctName, string pswd)
        {
            int retval = -1;
            try
            {
                // This is the hook to the stored procedures data layer
                QueriesTableAdapter dataAdapters = new QueriesTableAdapter();
                retval = dataAdapters.EditAccount(acctId, acctName, pswd);
                if (retval < 0)
                {
                    throw new DataUpdateException("Error updating account", "Account");
                }
            }
            catch (Exception ex)
            {
                throw new DataUpdateException(ex.Message, "Account");
            }
            return retval;
        }

        /// <summary>
        /// Addes a record to the Securities table
        /// </summary>
        /// <param name="ticker">Ticker symbol</param>
        /// <param name="company">Company name</param>
        /// <param name="type">Security Type</param>
        /// <returns></returns>
        public int AddTicker(string ticker, string company, string type)
        {
            int retval = -1;
            try
            {
                // This is the hook to the stored procedures data layer
                QueriesTableAdapter dataAdapters = new QueriesTableAdapter();
                retval = dataAdapters.AddSecurity(ticker, company, type);
                if (retval < 0)
                {
                    throw new DataUpdateException("Error adding security", "Securities");
                }
            }
            catch (Exception ex)
            {
                throw new DataUpdateException(ex.Message, "Securities");
            }
            return retval;
        }


        /// <summary>
        /// Returns the list of tickers associated with the selected company name.
        /// </summary>
        /// <param name="companyName">Company name</param>
        /// <returns>A datatable of the selected records</returns>
        public StocksDataSet.FindTickerDataTable FindTicker(string companyName)
        {
            StocksDataSet.FindTickerDataTable table = null;
            try
            {
                table = new StocksDataSet.FindTickerDataTable();
                FindTickerTableAdapter adapter = new FindTickerTableAdapter();
                adapter.Fill(table, companyName);
            }
            catch (Exception ex)
            {
                table = new StocksDataSet.FindTickerDataTable(); // swallow the error
                                                                 // and return an empty
                                                                 // list
            }
            return table;
        }

        /// <summary>
        /// Returns a reference list of all securities
        /// </summary>
        /// <returns></returns>
        public StocksDataSet.SecuritiesDataTable GetSecurities()
        {
            StocksDataSet.SecuritiesDataTable table = null;
            try
            {
                table = new StocksDataSet.SecuritiesDataTable();
                SecuritiesTableAdapter adapter = new SecuritiesTableAdapter();
                adapter.Fill(table);
            }
            catch (Exception ex)
            {
                throw new DataLoadException(ex.Message, "Securities");
            }
            return table;
        }

        /// <summary>
        /// Returns a reference list of all companies
        /// </summary>
        /// <returns></returns>
        public StocksDataSet.CompanyDataTable GetCompanies()
        {
            StocksDataSet.CompanyDataTable table = null;
            try
            {
                table = new StocksDataSet.CompanyDataTable();
                CompanyTableAdapter adapter = new CompanyTableAdapter();
                adapter.Fill(table);
            }
            catch (Exception ex)
            {
                throw new DataLoadException(ex.Message, "Company");
            }
            return table;
        }

        /// <summary>
        /// Returns a reference list of all security types
        /// </summary>
        /// <returns></returns>
        public StocksDataSet.SecTypeDataTable GetSecurityTypes()
        {
            StocksDataSet.SecTypeDataTable table = null;
            try
            {
                table = new StocksDataSet.SecTypeDataTable();
                SecTypeTableAdapter adapter = new SecTypeTableAdapter();
                adapter.Fill(table);
            }
            catch (Exception ex)
            {
                throw new DataLoadException(ex.Message, "SecType");
            }
            return table;
        }

        /// <summary>
        /// Returns a reference list of all trade types
        /// </summary>
        /// <returns></returns>
        public StocksDataSet.TradeTypesDataTable GetTradeTypes()
        {
            StocksDataSet.TradeTypesDataTable table = null;
            try
            {
                table = new StocksDataSet.TradeTypesDataTable();
                TradeTypesTableAdapter adapter = new TradeTypesTableAdapter();
                adapter.Fill(table);
            }
            catch (Exception ex)
            {
                throw new DataLoadException(ex.Message, "TradeTypes");
            }
            return table;
        }

        /// <summary>
        /// method for retrieving the data from the provided URL
        ///        array[0] = Symbol
        ///        array[1] = Last Price
        ///        array[2] = Date
        ///        array[3] = Time
        ///        array[4] = Change
        ///        array[5] = Open Price
        ///        array[6] = Day High Price
        ///        array[7] = Day Low Price
        ///        array[8] = Trade Volume        
        /// </summary>
        /// <param name="url">URL we're scraping</param>
        /// <returns></returns>
        public string[] LoadSiteContents(string url)
        {
            StreamReader stream = null;
            string[] results ;
            try
            {
                //create a new WebRequest object
                WebRequest request = WebRequest.Create(url);

                //create StreamReader to hold the returned request
                stream = new StreamReader(request.GetResponse().GetResponseStream());

                //return the information
                results = stream.ReadToEnd().Split(',');
            }
            catch (Exception ex)
            {
                return null;
            }
            finally
            {
                if (stream != null)
                {
                    //close up the StreamReader
                    stream.Close();
                }
            }
            return results;
        }

        public StocksDataSet.GetAccountPortfolioDataTable GetPortfolio(string acctId)
        {
            GetAccountPortfolioTableAdapter portfolioAdapter = new GetAccountPortfolioTableAdapter();
            StocksDataSet.GetAccountPortfolioDataTable portfolio = portfolioAdapter.GetData(acctId);
            return portfolio;
        }

        public StocksDataSet.AccountsRow GetAccountData(string username, string pswd)
        {
            AccountsTableAdapter accounts = new AccountsTableAdapter();
            StocksDataSet.AccountsDataTable tbl = accounts.GetData();
            var userAccount = (from user in tbl
                               where user.Password.Equals(pswd) &&
                               user.AccountID.Equals(username)
                               select user).FirstOrDefault();
            return userAccount;
        }

        public List<StocksDataSet.PricesRow> GetPrices(string ticker, DateTime start, DateTime end)
        {
            PricesTableAdapter pricesTable = new PricesTableAdapter();
            StocksDataSet.PricesDataTable prices = pricesTable.GetData();

            return prices.Where(p => p.Ticker.ToLower().Equals(ticker.ToLower()) && p.TradeDate >= start && p.TradeDate <= end).ToList();
        }
    }
}
